package com.shangguigu.stack.exc;

import java.util.Stack;

/**
 * @author: ZhouBert
 * @date: 2019/10/11
 * @description: 表达式计算：无括号的表达式,每个数字一位
 * 
 */
public class ExpressionCalc {


	/**
	 * 记录符号数等级--用这种结构很麻烦
	 */
	///public static HashMap<Integer, Character[]> levelMap = new HashMap<>();

	/**
	 * 自己通过思路编写的。似乎不够优雅，对比了下教材，基本一致。calculate 这个方法可以优化一下
	 *
	 * @param exp
	 * @return
	 */
	public static int calc(String exp) {
		///1.定义数字栈
		Stack<Integer> numStack = new Stack<>();
		///2.定义符号栈
		Stack<Character> lableStack = new Stack<>();

		char[] chars = exp.toCharArray();
		for (int i = 0; i < chars.length; i++) {
			///是数字则
			if (Character.isDigit(chars[i])) {
				///version1.一捕获到数字就入栈--但是存在多位数的BUG
				///todo:char 转 int 需要注意！
				///numStack.push(Integer.valueOf(chars[i])-Integer.valueOf('0'));

				///version2.一直追踪下一位判断是否为数字，直到为符号
				///数字的起始索引-beginIndex;符号数的起始索引-index
				int index=i+1,beginIndex=i;
				while (index < chars.length&&Character.isDigit(chars[index])){
					index++;
					i++;
				}
				///存储整形的变量
				String numStr = exp.substring(beginIndex, index);
				numStack.push(Integer.valueOf(numStr));

			} else if (lableStack.isEmpty()) {
				lableStack.push(chars[i]);
			} else if (!lableStack.isEmpty()) {
				///如果当前优先级大于栈顶元素
				if (isGreater(chars[i], lableStack.peek())) {
					lableStack.push(chars[i]);
				} else {
					int a = numStack.pop();
					///todo:注意晚出栈的元素作为前面的计算数
					int tempVal = calculate(numStack.pop(), a, lableStack.pop());
					numStack.push(tempVal);
					lableStack.push(chars[i]);
				}
			}

		}

		///处理剩下的符号栈元素
		while (!lableStack.isEmpty()){
			int a = numStack.pop();
			int tempVal = calculate(numStack.pop(), a, lableStack.pop());
			numStack.push(tempVal);
		}
		return numStack.pop();
	}


	/**
	 * c1 操作符级别是否大于 c2
	 *
	 * @param c1
	 * @param c2
	 * @return
	 */
	public static boolean isGreater(char c1, char c2) {
		return rank(c1) < rank(c2);
	}

	public static int  rank(char ch) {
		int ans = 0;
		switch (ch) {
			case '*':
			case '/':
				ans = 3;
				break;
			case '+':
			case '-':
				ans = 4;
				break;
			default:
				break;
		}
		return ans;
	}

	/**
	 * 可以将 a 和 b 的位置换一下，这样调用时可以简洁一些
	 * @param a
	 * @param b
	 * @param l
	 * @return
	 */
	public static int calculate(int a, int b, char l) {
		int ans = 0;
		switch (l) {
			case '+':
				ans = a + b;
				break;
			case '-':
				ans = a - b;
				break;
			case '*':
				ans = a * b;
				break;
			case '/':
				ans = a / b;
				break;
		}
		return ans;
	}

	public static void main(String[] args) {
//		String exp = "3+2*6-2";
//		System.out.println(calc(exp));
		String exp2 = "300+20*6-21";
		System.out.println(calc(exp2));
	}
}
